home *** CD-ROM | disk | FTP | other *** search
- Subject: v15i009: Wrapper for System V lp, bug work-around
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: utgpu!utfyzx!harrison (David Harrison)
- Posting-number: Volume 15, Issue 9
- Archive-name: lp-onionskin
-
- Here is a small program of use only for systems with the System V
- semaphore facility. It works around a bug in the lockfile mechanism
- of lp(1) that causes the spooler to periodically crash if it gets
- 2 or more jobs at almost the same time. The README file discusses
- further. To do the job right would nuke the lockfiles in lp(1)
- in favour of the System V ipcs facility, but that requires source
- (which I have) and time (which I don't have), so this is just
- an onionskin around lp(1).
- David Harrison, Dept. of Physics, Univ. of Toronto
- {ihnp4,utzoo}!utgpu!utfyzx!harrison
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # Makefile
- # README
- # lp.c
- # lock.c
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'Makefile'" '(435 characters)'
- if test -f 'Makefile'
- then
- echo shar: will not over-write existing file "'Makefile'"
- else
- sed 's/^X//' << \SHAR_EOF > 'Makefile'
- X# @(#)Makefile 1.1 U of T Physics 2/24/88
- X
- XSRC = lp.c lock.c
- XOBJS = lp.o lock.o
- XBIN = /usr/bin
- XLP = lp -s
- XLINTFLAGS = -DLINT
- X
- X# for symbolic debugger
- X# CFLAGS = -g
- X# CDBOBJ = /usr/lib/end.o
- X
- Xlptry: $(OBJS)
- X cc -o lptry $(OBJS) $(CDBOBJ)
- X
- Xinstall: lptry
- X strip lptry
- X mv $(BIN)/lp $(BIN)/real_lp
- X cpset lptry $(BIN) 0755
- X
- Xlint:
- X lint $(LINTFLAGS) $(SRC)
- X
- Xclean:
- X /bin/rm -f *.o core
- X
- Xprint: Makefile $(SRC)
- X pr $? | $(LP)
- X touch print
- SHAR_EOF
- if test 435 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: error transmitting "'Makefile'" '(should have been 435 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'README'" '(1519 characters)'
- if test -f 'README'
- then
- echo shar: will not over-write existing file "'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- XThe standard lp(1) spooler in System V uses a variety of
- Xlockfiles in processing a job. This leaves a window of
- Xvulnerability if two jobs are received nearly simultaneously:
- X
- X lp job 1 checks to see if there is a lockfile,
- X finds there isn't.
- X lp job 2 checks to see if there is a lockfile,
- X finds there isn't
- X lp job 1 establishes the lockfile
- X lp job 2 tries to establish the lockfile and fails.
- X
- XWhen this happens, the spooler croaks. Often the symptom is
- Xthat jobs start piling up for printing but none ever are,
- Xsometimes it is more gory than that. The fix is sometimes
- Xto disable(1) the printer and then enable(1) it. Sometimes
- Xthe only fix is to cancel(1) the pending jobs.
- X
- XThis small program is another fix. It moves /usr/bin/lp to
- X/usr/bin/real_lp, and subsitutes this program as /usr/bin/lp.
- XThus, you must be root to install the program.
- X
- XEssentially all this program does is throw up a semaphore,
- Xexecs real_lp, and lowers the semaphore.
- X
- XWe have been running this for two months without any failures
- Xor problems on an HP9000 Series 500 running Release 5.11 of
- XHP-UX (System V.2). Because our application involves up to
- X200 one-page prints per day from 20 scattered users, prior to
- Xits installation our spooler was hanging every couple of days
- Xor so average with peaks of 2 or 3 hangs a day.
- X
- XYou may want to check ipcs(1) and ipcrm(1) if you are unfamiliar
- Xwith the System V semaphore facility.
- X--
- X David Harrison, Dept. of Physics, Univ. of Toronto
- X {ihnp4,utzoo}!utgpu!utfyzx!harrison
- SHAR_EOF
- if test 1519 -ne "`wc -c < 'README'`"
- then
- echo shar: error transmitting "'README'" '(should have been 1519 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'lp.c'" '(2324 characters)'
- if test -f 'lp.c'
- then
- echo shar: will not over-write existing file "'lp.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'lp.c'
- X#ifndef LINT
- Xstatic char SccsId[] = "@(#)lp.c 1.2 U of T Physics 12/16/87";
- X#endif
- X
- X/*
- X * This is an onionskin around the lp spooler.
- X * The problem is that the standard lp(1) uses lockfiles, with
- X * the well-known window of vulnerability between testing for
- X * the existence of the file and trying to create it.
- X * Thus, we have moved the standard lp command to "real_lp",
- X * and this program becomes "lp".
- X * It uses a semaphore to lock and unlock jobs sent to lp.
- X * David Harrison - Dec/87
- X */
- X
- X#include <stdio.h>
- X#include <signal.h>
- X
- Xchar *real_lp_cmd = "real_lp";
- X
- Xchar *progname;
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X void _exit(), perror();
- X char *emalloc();
- X char *strcpy(), *strcat();
- X char **exec_argv;
- X int pid, w, status;
- X int (*istat)(), (*qstat)();
- X int i;
- X
- X progname = argv[0];
- X
- X /*
- X * put arguments from argv into exec_argv, terminating
- X * with a null.
- X *
- X * First malloc the array size needed ( with one for the NULL
- X * and the end).
- X */
- X exec_argv =
- X (char **) emalloc( (unsigned) ((argc + 1) * sizeof (char *) ));
- X /*
- X * Put real_lp_cmd in argv[0]
- X */
- X exec_argv[0] = emalloc( (unsigned) (strlen(real_lp_cmd) + 1) );
- X (void) strcpy(exec_argv[0], real_lp_cmd);
- X /*
- X * Now the other argements
- X */
- X if( argc > 1) {
- X for(i = 1; i < argc; i++) {
- X exec_argv[i] = emalloc( (unsigned) (strlen(argv[i]) + 1 ));
- X (void) strcpy(exec_argv[i], argv[i]);
- X }
- X }
- X /*
- X * Terminate with a NULL
- X */
- X exec_argv[argc] = NULL;
- X
- X lockproc();
- X
- X switch( (pid = fork()) ) {
- X
- X case -1:
- X unlockproc();
- X Sys_Error("Can't fork\n");
- X break;
- X
- X case 0:
- X execvp( real_lp_cmd , exec_argv );
- X unlockproc();
- X fprintf(stderr,"%s: can't exec %s\n",
- X progname, real_lp_cmd );
- X perror("exec");
- X _exit(127);
- X
- X default:
- X break;
- X
- X }
- X
- X /*
- X * Trap signals and wait for child to finish.
- X */
- X istat = signal(SIGINT, SIG_IGN);
- X qstat = signal(SIGQUIT, SIG_IGN);
- X while( (w = wait(&status)) != pid && w != -1)
- X ;
- X if( w == -1)
- X status = -1;
- X signal(SIGINT, istat);
- X signal(SIGQUIT, qstat);
- X
- X unlockproc();
- X
- X return status;
- X
- X}
- X
- Xchar *
- Xemalloc(n)
- Xunsigned n;
- X{
- X char *p, *malloc();
- X
- X p = malloc(n);
- X if ( p == 0)
- X Sys_Error("Out of memory");
- X return p;
- X}
- X
- XSys_Error(s)
- Xchar *s;
- X{
- X void exit(), perror();
- X
- X fprintf(stderr,"%s: %s\n",progname, s);
- X perror("terminating");
- X exit(1);
- X
- X}
- SHAR_EOF
- if test 2324 -ne "`wc -c < 'lp.c'`"
- then
- echo shar: error transmitting "'lp.c'" '(should have been 2324 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'lock.c'" '(2776 characters)'
- if test -f 'lock.c'
- then
- echo shar: will not over-write existing file "'lock.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'lock.c'
- X#ifndef LINT
- Xstatic char SccsId[] = "@(#)lock.c 1.1 U of T Physics 12/15/87";
- X#endif
- X
- X/*
- X * Standard lp creates lockfiles to suspend a second request.
- X * This leaves a small window of vulnerability if 2 users
- X * are using the program at one time.
- X *
- X * This file contains:
- X * lockproc() - which locks so other user can use
- X * the program.
- X * unlockproc() - which unlocks for other users.
- X *
- X * It uses the semaphore facility and is highly system dependent.
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/ipc.h>
- X#include <sys/sem.h>
- X#include <errno.h>
- X
- X/*
- X * The following are the way to get a key out of ftok()
- X */
- X#define PATH "/usr/bin/real_lp"
- X#define ID 'a'
- X
- X#define UNLOCK (1)
- X#define LOCK (-1) /* impossible, so will lock */
- X
- X#define MODE (0666) /* rw by the world */
- X
- X/*
- X * If the owner removes the facility while a 2nd process is
- X * waiting to lock it, the second process will receive an
- X * error from semop(2). Thus, we try TRIES times to lock
- X * the process.
- X */
- X#define TRIES 5
- X
- X#define YES 1
- X#define NO 0
- X
- Xstatic int sid; /* semaphore id number */
- Xstatic short creator; /* == YES if this process created */
- X
- Xextern char *progname;
- X
- Xlockproc()
- X{
- X int sem_flg, numbad;
- X key_t key, ftok();
- X struct sembuf sb;
- X
- X numbad = 0;
- X
- Xretry:
- X
- X if((key = ftok(PATH,ID)) == -1)
- X Lock_Error("Cannot get ipc key");
- X
- X
- X errno = 0;
- X creator = NO;
- X
- X if(numbad >= TRIES) {
- X if(creator == YES)
- X semctl(sid, IPC_RMID, 0);
- X Lock_Error("Lock error");
- X }
- X
- X sem_flg = MODE | IPC_CREAT | IPC_EXCL;
- X
- X sid = semget(key, 1, sem_flg);
- X if(sid == -1 && errno == EEXIST) {
- X /*
- X * In use by another user.
- X */
- X sem_flg = MODE;
- X (void) fflush(stdout);
- X sid = semget(key, 1, sem_flg);
- X /* it will get here, but then block */
- X } else {
- X creator = YES;
- X if(semctl(sid, 0, SETVAL, UNLOCK) == -1) {
- X semctl(sid, 0, IPC_RMID, 0);
- X Lock_Error("Cannot create semaphore");
- X }
- X }
- X
- X sb.sem_num = 0; /* 1st semaphore */
- X sb.sem_op = LOCK; /* we are locking the semaphore */
- X sb.sem_flg = SEM_UNDO; /* auto reverse */
- X
- X if (semop(sid, &sb, 1) == -1) {
- X if( errno == EINTR || errno == EIDRM) {
- X numbad++;
- X goto retry;
- X } else {
- X Lock_Error("Cannot semop()");
- X }
- X }
- X}
- X
- Xunlockproc()
- X{
- X struct sembuf sb;
- X
- X if(creator == YES) {
- X if(semctl(sid, IPC_RMID, 0) != 0) {
- X Lock_Error("Cannot remove lock");
- X }
- X } else {
- X sb.sem_num = 0;
- X sb.sem_op = UNLOCK;
- X sb.sem_flg = SEM_UNDO;
- X
- X if(semop(sid, &sb, 1) == -1)
- X Lock_Error("Cannot unlock");
- X }
- X}
- X
- XLock_Error(s)
- Xchar *s;
- X{
- X void exit();
- X extern char *progname;
- X
- X fprintf(stderr,"%s: please notify your system administrator\n",
- X progname);
- X fprintf(stderr,"that you received the following error message:\n");
- X fprintf(stderr," ***** %s *****\n", s);
- X fprintf(stderr,"Your print job has aborted.\n");
- X exit(1);
- X}
- SHAR_EOF
- if test 2776 -ne "`wc -c < 'lock.c'`"
- then
- echo shar: error transmitting "'lock.c'" '(should have been 2776 characters)'
- fi
- fi # end of overwriting check
- # End of shell archive
- exit 0
-